﻿namespace Jhong.OWINSession
{
    using Jhong.OWINSession.OWINCookie;
    using System;
    using System.Collections.Generic;
    using Env = System.Collections.Generic.IDictionary<string, object>;

    public class DefaultSessionManager : ISessionManager
    {
        private static DefaultSessionManager _manager;

        private static object _lock = new object();

        public static DefaultSessionManager Manager
        {
            get
            {
                lock (_lock)
                {
                    if (null == _manager) _manager = new DefaultSessionManager();
                    return _manager;
                }
            }
        }

        private DefaultSessionManager()
        {
            switch (OWINSessionOption.OSOption.SessionMode)
            {
                case SessionMode.InProcess: this._operaFunc = InProcess.InProcessFactory.InProcessInstance; break;
                case SessionMode.StateServer:
                    break;
            }
        }

        private Func<ISessionOpera> _operaFunc;

        private ISessionOpera _operaInstance
        {
            get
            {
                return this._operaFunc();
            }
        }

        internal void UpdateTimeOut(Env env)
        {
            var sessionID = GetCurrentSessionID(env);
            this._operaInstance.SetTimeOut(sessionID);
        }

        private string GetCurrentSessionID(Env env)
        {
            var reqCookie = new RequestCookieCollection(CookieFactory.GetCookies(env));
            var sessionIDStr = reqCookie[OWINSessionOption.SessionIDName];
            if (false == string.IsNullOrWhiteSpace(sessionIDStr))
            {
                if (this._operaInstance.CheckExists(sessionIDStr)) return sessionIDStr;
            }
            else
            {
                sessionIDStr = Guid.NewGuid().ToString();
            }

            var session = new Session();
            this._operaInstance.SetSession(sessionIDStr, session);
            env.Get<IDictionary<string, string[]>>("owin.RequestHeaders").Add("tmpSessionID", new string[] { sessionIDStr });
            var repCookie = new ResponseCookieCollection(env);
            repCookie.Append(OWINSessionOption.SessionIDName, sessionIDStr);
            return sessionIDStr;
        }

        public object GetSession(string sessionID, string key)
        {
            return this._operaInstance.GetSession(sessionID)[key];
        }

        public void SetSession(string sessionID, string key, object value)
        {
            var session = this._operaInstance.GetSession(sessionID);
            session[key] = value;
            this._operaInstance.SetSession(sessionID, session);
        }
    }
}